package com.xiaouyudeguang.common.entity;

import cn.org.atool.fluent.mybatis.annotation.LogicDelete;
import cn.org.atool.fluent.mybatis.annotation.NotField;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.JsonNode;
import com.mybatisflex.annotation.KeyType;
import com.xiaouyudeguang.common.request.RequestDto;
import com.xiaouyudeguang.common.respose.ResultDto;
import com.xiaouyudeguang.common.utils.JsonObject;
import com.xiaouyudeguang.common.utils.SecurityUtils;
import com.xiaouyudeguang.common.utils.Status;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.Transient;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Data
@MappedSuperclass
@NoArgsConstructor
@AllArgsConstructor
@ExcelIgnoreUnannotated
@JsonInclude(JsonInclude.Include.NON_NULL)
public class BaseEntity implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @JsonIgnore
    @com.mybatisflex.annotation.Id(keyType = KeyType.Auto)
    @Column(columnDefinition = "bigint comment '主键id'")
    protected Long id;

    /**
     * 创建人
     */
    @JsonIgnore
    @TableField(fill = FieldFill.INSERT)
    @Column(columnDefinition = "varchar(50) comment '创建人'")
    protected String creator;

    /**
     * 修改人
     */
    @JsonIgnore
    @TableField(fill = FieldFill.INSERT_UPDATE)
    @Column(columnDefinition = "varchar(50) comment '修改人'")
    protected String modifier;

    /**
     * 创建时间
     */
    @JsonIgnore
    @TableField(fill = FieldFill.INSERT)
    @Column(columnDefinition = "datetime(0) comment '创建时间'")
    protected LocalDateTime created;

    /**
     * 修改时间
     */
    @JsonIgnore
    @TableField(fill = FieldFill.INSERT_UPDATE)
    @Column(columnDefinition = "datetime(0) comment '修改时间'")
    protected LocalDateTime modified;

    @TableField(typeHandler = JacksonTypeHandler.class)
    @cn.org.atool.fluent.mybatis.annotation.TableField(typeHandler = JacksonTypeHandler.class)
    @Column(nullable = true, columnDefinition = "json comment '扩展字段'")
    protected LinkedHashMap<String, Object> extension;

    @JsonIgnore
    @LogicDelete
    @TableLogic(value = "0", delval = "now()")
    @com.mybatisflex.annotation.Column(isLogicDelete = true)
    @Column(columnDefinition = "bigint NULL DEFAULT 0 comment '状态'")
    protected Long status;

    @Column(nullable = false, columnDefinition = "int default 1 comment '是否已产生关联数据'")
    protected Boolean isUsed;

    @NotField
    @Transient
    @TableField(exist = false)
    @com.mybatisflex.annotation.Column(ignore = true)
    protected String label;

    @NotField
    @Transient
    @TableField(exist = false)
    @com.mybatisflex.annotation.Column(ignore = true)
    protected String ownerUserNames;

    @NotField
    @Transient
    @TableField(exist = false)
    @com.mybatisflex.annotation.Column(ignore = true)
    protected String ownerDeptNames;

    @NotField
    @Transient
    @TableField(exist = false)
    @com.mybatisflex.annotation.Column(ignore = true)
    protected Set<String> ownDeptList;

    @NotField
    @Transient
    @TableField(exist = false)
    @com.mybatisflex.annotation.Column(ignore = true)
    protected List<Map<String, String>> ownUserList;

//    @NotField
//    @Transient
//    @TableField(exist = false)
//    @com.mybatisflex.annotation.Column(ignore = true)
//    protected List<?> childrens;

    public String getEntityId() {
        return id == null ? null : String.valueOf(id);
    }

    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
    public LocalDateTime getCreateTime() {
        return created;
    }

    @SuppressWarnings("unchecked")
    public <T> T fill() throws Exception {
        this.setId(IdWorker.getId());
        this.setStatus(Status.NORMAL);
        try {
            this.setCreator(SecurityUtils.getUserId());
            this.setModifier(SecurityUtils.getUserId());
        } catch (Exception e) {
            this.setCreator("system");
            this.setModifier("system");
        }
        this.setCreated(LocalDateTime.now());
        this.setModified(LocalDateTime.now());
        return (T) this;
    }

    @JsonIgnore
    @SuppressWarnings("unchecked")
    public <T> RequestDto<T> getPage(Integer current, Integer size) {
        return (RequestDto<T>) RequestDto.getRequest(this).getPage(current, size);
    }

    @JsonIgnore
    @SuppressWarnings("unchecked")
    public <T> RequestDto<T> getRequest(String startTime, String endTime) {
        RequestDto<T> requestDto = (RequestDto<T>) RequestDto.getRequest(this);
        requestDto.setStartTime(startTime);
        requestDto.setEndTime(endTime);
        return requestDto;
    }

    @JsonIgnore
    @SuppressWarnings("unchecked")
    public <T> RequestDto<T> getRequest() {
        return (RequestDto<T>) RequestDto.getRequest(this);
    }

    @JsonIgnore
    @SuppressWarnings("unchecked")
    public <T> ResultDto<T> getResult() {
        return (ResultDto<T>) ResultDto.ok(this);
    }

    @JsonIgnore
    public JsonNode toNode() {
        return JsonObject.fromJson(this);
    }

    @Override
    public String toString() {
       return JsonObject.toJson(this);
    }
}
